/**
  ******************************************************************************
  * @file    Libraries/Device/TS32Fx/TS32Fx_LL_Driver/src/ts32fx_ll_eflash.c
  * @author  TOPSYS Application Team
  * @version V1.0.0
  * @date    02-11-2018
  * @brief   This file contains all the EFLASH LL firmware functions.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2018 TOPSYS</center></h2>
  *
  *
  *
  ******************************************************************************
  */ 

/* Includes ------------------------------------------------------------------*/
#include "include.h"
#include "ts32fx_ll_eflash.h"

/** @addtogroup TS32Fx_StdPeriph_Driver TS32Fx Driver
  * @{
  */
  
/** @defgroup eflash_interface_gr EFLASH Driver
  * @ingroup  TS32Fx_StdPeriph_Driver
  * @{
  */

/** @addtogroup EFLASH_LL_Driver EFLASH LL Driver
  * @ingroup  eflash_interface_gr
  * @{
  */
  
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

  
/** @defgroup EFLASH_LL_Interrupt EFLASH LL Interrupt Handle function
  * @ingroup  EFLASH_LL_Driver
  * @brief   EFLASH LL Interrupt Handle function
  * @{
  */



/**
  * @}
  */

/** @defgroup EFLASH_LL_Inti_Cfg EFLASH LL Initialization And Configuration
  * @ingroup  EFLASH_LL_Driver
  * @brief    EFLASH LL Initialization And Configuration
  * @{
  */

/**
  * @brief  ll_eflash_init
  * @param  p_eflash: Base address of eflash register
  * @param  p_init: TYPE_LL_EFLASH_INIT pointer to eflash init stuct
  * @retval None
  * @note eflash clk : 26Mhz safty, but Need to be set to 8M on the FPGA
  */
void ll_eflash_init(EFLASH_TypeDef *p_eflash, TYPE_LL_EFLASH_INIT *p_init)
{
#if FPGA_EN
#define RC_TIME         (((SYS_CLK/1000000 + 7)/8)-1)
#else
#define RC_TIME         (((SYS_CLK/1000000 + 25)/26)-1)
#endif
    ll_eflash_timing_set(
        p_eflash, 
        LL_EF_TIME_REG0_RC(RC_TIME)|LL_EF_TIME_REG0_RW(4)|LL_EF_TIME_REG0_ADH(0)|LL_EF_TIME_REG0_ADS(4)|LL_EF_TIME_REG0_PGH(0),
        LL_EF_TIME_REG1_US(((SYS_CLK/1000000) + 2)) | LL_EF_TIME_REG1_MS(1000)
    );

    //eflash_main_lock(EFLASHx, UNLOCK);
    //eflash_nvr_lock(EFLASHx, UNLOCK);

    ll_eflash_clk_sel(p_eflash, LL_EF_PROG_CLK_RC2DIV);
    
}

/**
  * @brief  ll_eflash_deinit
  * @param  p_eflash: EFLASH_TypeDef pointer to eflash hardware register
  * @retval None
  * @note eflash clk 26Mhz safty, but Need to be set to 8M on the FPGA
  */
void ll_eflash_deinit(EFLASH_TypeDef *p_eflash)
{
    TX_ASSERT(EFLASH == p_eflash);

}


/**
  * @brief  ll_eflash_nvr_lock
  * @param  p_eflash: Base address of eflash register
  * @param  isLock: Whether to lock
  * @retval None
  */
void ll_eflash_nvr_lock(EFLASH_TypeDef *p_eflash, TYPE_ENUM_LL_EF_LOCK isLock){
    if(isLock){
        p_eflash->NVR_PASSWORD = 0x0;
    } else {
        p_eflash->NVR_PASSWORD = LL_EF_HW_NVR_PASSWORD;
    }
}

/**
  * @brief  ll_eflash_main_lock
  * @param  p_eflash: Base address of eflash register
  * @param  isLock: Whether to lock
  * @retval None
  */
void ll_eflash_main_lock(EFLASH_TypeDef *p_eflash, TYPE_ENUM_LL_EF_LOCK isLock){
    if(isLock){
        p_eflash->MAIN_PASSWORD = 0x0;
    } else {
        p_eflash->MAIN_PASSWORD = LL_EF_HW_MAIN_PASSWORD;
    }
}

/**
  * @brief  ll_eflash_timing_set
  * @param  p_eflash: Base address of eflash register
  * @param  time_reg0: timer register0
  * @param  time_reg1: timer register1
  * @retval None
  */
void ll_eflash_timing_set(EFLASH_TypeDef *p_eflash, 
                       u32 time_reg0,
                       u32 time_reg1)
{
    p_eflash->TIME_REG0 = time_reg0;
    /* p_eflash->TIME_REG1 = time_reg1 & 0xFF; */
}

/**
  * @brief  ll_eflash_clk_sel_exosc
  * @param  p_eflash: Base address of eflash register
  * @retval None
  * @note osc clk : 26Mhz
  */
void ll_eflash_clk_sel(EFLASH_TypeDef *p_eflash, TYPE_ENUM_LL_EF_PROG_CLK_SEL exosc_sel)
{
    if(LL_EF_PROG_CLK_EXOSC == exosc_sel){
        p_eflash->CTRLR0 |= LL_EF_CTRLR0_PROG_CLK_EXOSC_SEL;
    } else {
        p_eflash->CTRLR0 &= ~LL_EF_CTRLR0_PROG_CLK_EXOSC_SEL;
    }
}

/**
  * @brief  ll_eflash_prefetch_set
  * @param  p_eflash: Base address of eflash register
  * @param  on: 1: prefetch enable, 0:prefetch disable
  * @retval None
  */
void ll_eflash_prefetch_set(EFLASH_TypeDef *p_eflash, BOOL on)
{
    if( on ) {
        p_eflash->CTRLR0 |= LL_EF_CTRLR0_PREFETCH_EN;
    } else {
        p_eflash->CTRLR0 &= ~LL_EF_CTRLR0_PREFETCH_EN;
    }
}

/**
  * @brief  ll_eflash_cache_set
  * @param  p_eflash: Base address of eflash register
  * @param  on: 1: cache enable, 0:cache disable
  * @retval None
  */
void ll_eflash_cache_set(EFLASH_TypeDef *p_eflash, BOOL on)
{
    if( on ) {
        p_eflash->CTRLR0 |= LL_EF_CTRLR0_CACHE_EN;
    } else {
        p_eflash->CTRLR0 &= ~LL_EF_CTRLR0_CACHE_EN;
    }
}

/**
  * @}
  */

/** @defgroup EFLASH_LL_Data_Transfers EFLASH LL Data transfers functions
  * @ingroup  EFLASH_LL_Driver
  * @brief    EFLASH LL Data transfers functions 
  * @{
  */

/**
  * @brief  ll_eflash_cache_data_clr
  * @param  p_eflash: Base address of eflash register
  * @retval None
  */
void ll_eflash_cache_data_clr(EFLASH_TypeDef *p_eflash){
    p_eflash->KST = LL_EF_KST_CACHE_CLR_KICK_START;
}

/**
  * @brief  ll_eflash_prog_one_data
  * @param  p_eflash: Base address of eflash register
  * @param  addr: Write data address in eflash
  * @param  data: Write data to eflash
  * @retval None
  */
void ll_eflash_prog_one_data(EFLASH_TypeDef *p_eflash, u32 addr, u32 data)
{
    while((p_eflash->DONE & LL_EF_DONE_PROG_DONE) != LL_EF_DONE_PROG_DONE);
    
    ll_eflash_main_lock(p_eflash, LL_EF_UNLOCK);
    
    p_eflash->PROG_ADDR = LL_EF_PROG_ADDR_PROG_BYTE_ADDR(addr);
    
    p_eflash->PROG_DATA = data;

    while((p_eflash->DONE & LL_EF_DONE_PROG_DONE) != LL_EF_DONE_PROG_DONE);
}

/**
  * @brief  ll_eflash_prog_one_data_nvr
  * @param  p_eflash: Base address of eflash register
  * @param  addr: Write data address in eflash
  * @param  data: Write data to eflash
  * @retval None
  */
void ll_eflash_prog_one_data_nvr(EFLASH_TypeDef *p_eflash, u32 addr, u32 data)
{
    while((p_eflash->DONE & LL_EF_DONE_PROG_DONE) != LL_EF_DONE_PROG_DONE);
    
    ll_eflash_nvr_lock(p_eflash, LL_EF_UNLOCK);
    
    p_eflash->PROG_ADDR = LL_EF_PROG_ADDR_PROG_BYTE_ADDR(addr) |
                          LL_EF_PROG_ADDR_PROG_NVR_EN;
  
    p_eflash->PROG_DATA = data;

    while((p_eflash->DONE & LL_EF_DONE_PROG_DONE) != LL_EF_DONE_PROG_DONE);
}

/**
  * @brief  ll_eflash_erase_one_sector
  * @param  p_eflash: Base address of eflash register
  * @param  sect_addr: The address of the sector in eflash
  * @retval None
  */
void ll_eflash_erase_one_sector(EFLASH_TypeDef *p_eflash, u16 sect_addr)
{
    while((p_eflash->DONE & LL_EF_DONE_SECT_ERASE_DONE) != LL_EF_DONE_SECT_ERASE_DONE);
    
    ll_eflash_main_lock(p_eflash, LL_EF_UNLOCK);

    p_eflash->ERASE_CTRL = LL_EF_ERASE_CTRL_SECTOR_ERASE_KICK_START | LL_EF_ERASE_CTRL_ERASE_SECTOR_ADDR(sect_addr);
    
    while((p_eflash->DONE & LL_EF_DONE_SECT_ERASE_DONE) != LL_EF_DONE_SECT_ERASE_DONE);
}

/**
  * @brief  ll_eflash_erase_one_sector_NVR
  * @param  p_eflash: Base address of eflash register
  * @param  sect_addr: The address of the sector in eflash
  * @retval None
  */
void ll_eflash_erase_one_sector_nvr(EFLASH_TypeDef *p_eflash, u16 sect_addr)
{
    while((p_eflash->DONE & LL_EF_DONE_SECT_ERASE_DONE) != LL_EF_DONE_SECT_ERASE_DONE);

    ll_eflash_nvr_lock(p_eflash, LL_EF_UNLOCK);

    p_eflash->ERASE_CTRL = LL_EF_ERASE_CTRL_SECTOR_ERASE_KICK_START |
                           LL_EF_ERASE_CTRL_SECTOR_NVR_SEL |
                           LL_EF_ERASE_CTRL_ERASE_SECTOR_ADDR(sect_addr);
    while((p_eflash->DONE & LL_EF_DONE_SECT_ERASE_DONE) != LL_EF_DONE_SECT_ERASE_DONE);
}


/**
  * @brief  ll_eflash_erase_chip
  * @param  p_eflash: Base address of eflash register
  * @retval None
  */
void ll_eflash_erase_chip(EFLASH_TypeDef *p_eflash)
{
    while((p_eflash->DONE & LL_EF_DONE_CHIP_ERASE_DONE) != LL_EF_DONE_CHIP_ERASE_DONE);
    
    ll_eflash_main_lock(p_eflash, LL_EF_UNLOCK);

    p_eflash->ERASE_CTRL = LL_EF_ERASE_CTRL_CHIP_ERASE_KICK_START;
    while((p_eflash->DONE & LL_EF_DONE_CHIP_ERASE_DONE) != LL_EF_DONE_CHIP_ERASE_DONE);

    ll_eflash_cache_data_clr(p_eflash);
}


/**
  * @brief  ll_eflash_crc_calc
  * @param  p_eflash: Base address of eflash register
  * @param  st_address: phsic_addr, align: 4byte
  * @param  len :  align: 4byte  
  * @retval crc32 result
  */
u32 ll_eflash_crc32(EFLASH_TypeDef *p_eflash, u32 st_addr, u32 len)
{
#if  CRC_CHECK_EN
    if(st_addr >= LL_EF_NVR_BASE) {
        p_eflash->CRC_ADDR = LL_EF_CRC_DMA_ADDR_NVR_EN |
                             LL_EF_CRC_DMA_ADDR(st_addr-LL_EF_NVR_BASE);
    } else {
        p_eflash->CRC_ADDR = st_addr;
    }
    p_eflash->CRC_LEN = len;

    p_eflash->KST |= LL_EF_KST_CRC_DMA_KICK_START | LL_EF_KST_CRC_DMA_KICK_EN;
    while(0 == (p_eflash->DONE & LL_EF_DONE_CRC_DONE));
    return p_eflash->CRC_OUT;
#else
#warning "CRC CHECK MUST EN!!!"
    return 0;
#endif
}

/**
  * @brief  ll_eflash_auto_program
  * @param  p_eflash: Base address of eflash register
  * @param  ef_addr: eflash main phsic_addr, align: 4byte
  * @param  ram_addr: sram start address, align: 4byte
  * @param  len :  align: 4byte  
  * @retval crc32 result
  */
void ll_eflash_auto_program(EFLASH_TypeDef *p_eflash, u32 ef_addr, u32 ram_addr, u32 len)
{
    while((p_eflash->DONE & (LL_EF_DONE_PROG_DONE)) == 0);

    p_eflash->CTRLR0 |= LL_EF_CTRLR0_AUTO_PROGRAM_MODE;

    p_eflash->PROG_ADDR = LL_EF_PROG_ADDR_PROG_BYTE_ADDR(ef_addr);
    
    p_eflash->CRC_ADDR = ram_addr;
    p_eflash->CRC_LEN = len;

    p_eflash->KST |= LL_EF_KST_CRC_DMA_KICK_START | LL_EF_KST_CRC_DMA_KICK_EN;
    while(0 == (p_eflash->DONE & LL_EF_DONE_CRC_DONE));
    
    p_eflash->CTRLR0 &= ~LL_EF_CTRLR0_AUTO_PROGRAM_MODE;
    
}

/**
  * @brief  ll_eflash_crc_out_result_get
  * @param  p_eflash: Base address of eflash register
  * @retval crc result
  * @note   CRC results, polynomial crc-32 is as follows, the results out of the inverse is the official results  
            write EFLASH CRC need to take the official value of the inverse!!!  
            X32 + x26 + x23 + x22 + x16 + x12 + x11 + + by 8 x10 + + x 5 x7 + x4 + x2 + x + 1  
  */
u32 ll_eflash_crc_out_result_get(EFLASH_TypeDef *p_eflash)
{
    return (u32)(p_eflash->CRC_OUT);
}

/**
  * @brief  ll_eflash_cfg_sector_main_get
  * @param  p_eflash: Base address of eflash register
  * @retval cfg sector
  * @note   Sector location configured by the MAIN user
  */
u32 ll_eflash_cfg_sector_main_get(EFLASH_TypeDef *p_eflash)
{
    return (p_eflash->CFG_SECTOR);
}

/**
  * @brief  get chip id
  * @param  None
  * @retval ID
  * @note  
  */
u32 ll_chip_id_get(void)
{
    u32 *chip_id_addr = ((unsigned int *)0x1ff00600);
    u32 temp0 = 0;
    u32 temp1 = 0;

    temp0 = *chip_id_addr++;
    temp1 = *chip_id_addr;
    
    temp0 &= ~(((uint32_t)0x11)<<30);//~(3<<30);
    temp1 &= 0xff;
    temp1 %= 4;  
    temp0 |= (temp1<<30);
    
    return temp0;
}

/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

/*************************** (C) COPYRIGHT 2018 TOPSYS ***** END OF FILE *****/
